﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace FileUploadApp
{
    public partial class Service1 : ServiceBase
    {
        private const int MaxRetryAttempts = 3; // 最大重试次数
        private const int RetryDelayMilliseconds = 5000; // 重试延迟时间

        public Service1()
        {
            InitializeComponent();
        }

        private System.Timers.Timer timer;
        private bool isRunning = false;
        private const int BufferSize = 4096 * 1024; // 4MB缓冲区

        protected override void OnStart(string[] args)
        {
            Start();
        }

        protected override void OnStop()
        {
            try
            {
                var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lastFile.json");
                using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
                using (var writer = new StreamWriter(stream, Encoding.UTF8))
                {
                    writer.Write(Newtonsoft.Json.JsonConvert.SerializeObject(LoginUser.lastFile));
                }
            }
            catch (Exception ex)
            {
                Log.log("OnStop", $"保存lastFile异常：{ex.Message}");
            }

            try
            {
                if (timer != null)
                {
                    timer.Stop();
                    timer.Elapsed -= Timer_Elapsed;
                    timer.Dispose();
                    timer = null;
                }
                isRunning = false;
            }
            catch (Exception ex)
            {
                Log.log("OnStop", $"停止定时器异常：{ex.Message}");
            }
        }

        public void Start()
        {
            Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
            LoginUser.Regedit();
            LoginUser.InterfaceUrl = ConfigurationManager.AppSettings["InterfaceUrl"];
            LoginUser.FilePath = ConfigurationManager.AppSettings["FilePath"];
            LoginUser.CzId = Convert.ToInt32(ConfigurationManager.AppSettings["CZId"]);

            ReadFile();

            var interval = int.Parse(ConfigurationManager.AppSettings["TimerInterval"] ?? "10000");
            timer = new System.Timers.Timer(interval);
            timer.Elapsed += Timer_Elapsed;
            timer.Start();
        }

        private async void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (isRunning) { return; }
            isRunning = true;
            try
            {
                await Upload(LoginUser.lastFile.LastPicTime, LoginUser.lastFile.LastRwjlTime, LoginUser.lastFile.LastVideoTime);
            }
            finally
            {
                isRunning = false;
            }
        }

        public async Task Upload(DateTime dt1, DateTime dt2, DateTime dt3)
        {
            try
            {
                Log.log("dt1,dt2,dt3", $"dt1:{dt1:yyyy-MM-dd HH:mm:ss},dt2:{dt2:yyyy-MM-dd HH:mm:ss},dt3:{dt3:yyyy-MM-dd HH:mm:ss}");
                var endTime = DateTime.Now.AddMinutes(-15);

                var tasks = new List<Task>
                    {
                        UploadPic("pic", Path.Combine(LoginUser.FilePath, "pic"), LoginUser.CzId, dt1, endTime),
                        UploadPic("rwjl", Path.Combine(LoginUser.FilePath, "rwjl"), LoginUser.CzId, dt2, endTime),
                        UploadPic("video", Path.Combine(LoginUser.FilePath, "video"), LoginUser.CzId, dt3, endTime)
                    };
                await Task.WhenAll(tasks);
            }
            catch (Exception ex)
            {
                Log.log("Upload", $"上传异常：{ex.Message}");
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="preDir">从目标文件夹中获取子类图片的文件目录 如pic rwjh video</param>
        /// <param name="dirPath">FilePath 配置文件中的路径</param>
        /// <param name="czId"></param>
        /// <param name="lasttime">程序记录的最后同步时间 如lastpic 等</param>
        /// <param name="endtime">当前系统时间往前移动15分钟</param>
        /// <returns></returns>
        public async Task UploadPic(string preDir, string dirPath, int czId, DateTime lasttime, DateTime endtime)
        {
            if (!Directory.Exists(dirPath))
            {
                Log.log("UploadPic", $"目录不存在：{dirPath}");
                return;
            }

            try
            {
                DirectoryInfo di = new DirectoryInfo(dirPath);
                var fileViews = GetFileViews(di, lasttime, endtime, preDir).OrderBy(o => o.DateTime);

                foreach (var fi in fileViews)
                {
                    try
                    {
                        string base64String;
                        using (var stream = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize))
                        {
                            base64String = await ConvertStreamToBase64Async(stream);
                        }

                        var obj = new UploadFileObj
                        {
                            FileName = Path.GetFileName(fi.FullName),
                            Dir = $"{preDir}/{fi.Dir}",
                            Base64 = base64String,
                            czId = czId
                        };

                        bool succ = await RetryPolicy(async () => await APIService.UploadFile(obj));
                        if (!succ)
                        {
                            Log.log("UploadPic", $"{fi.FullName}上传异常：{APIService.errMsg}");
                        }
                        else
                        {
                            UpdateLastTime(preDir, fi.DateTime);
                        }

                        base64String = null;
                    }
                    catch (Exception ex)
                    {
                        Log.log("UploadPic", $"{fi.FullName}上传异常：{ex.Message}");
                    }
                }

                if (!fileViews.Any())
                {
                    UpdateLastTime(preDir, endtime);
                }
            }
            catch (Exception ex)
            {
                Log.log("UploadPic", $"处理目录异常：{ex.Message}");
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="di">配置文件路径</param>
        /// <param name="lasttime">最近各类型同步时间</param>
        /// <param name="endtime">当前系统时间往前15分钟</param>
        /// <param name="preDir">pic rwjh 等文件</param>
        /// <returns></returns>
        private IEnumerable<FileView> GetFileViews(DirectoryInfo di, DateTime lasttime, DateTime endtime, string preDir)
        {
            foreach (var d in di.EnumerateDirectories())
            {
                foreach (var file in d.EnumerateFiles().Where(o => o.LastWriteTime > lasttime && o.LastWriteTime <= endtime))
                {
                    yield return new FileView
                    {
                        DateTime = file.LastWriteTime,
                        Dir = d.Name,
                        FullName = file.FullName
                    };
                }
            }
        }

        private async Task<string> ConvertStreamToBase64Async(Stream stream)
        {
            using (var memoryStream = new MemoryStream())
            {
                await stream.CopyToAsync(memoryStream);
                return Convert.ToBase64String(memoryStream.ToArray());
            }
        }

        private void UpdateLastTime(string preDir, DateTime time)
        {
            if (preDir == "pic")
            {
                LoginUser.lastFile.LastPicTime = time;
            }
            else if (preDir == "rwjl")
            {
                LoginUser.lastFile.LastRwjlTime = time;
            }
            else if (preDir == "video")
            {
                LoginUser.lastFile.LastVideoTime = time;
            }
        }

        private async Task<bool> RetryPolicy(Func<Task<bool>> action)
        {
            for (int attempt = 1; attempt <= MaxRetryAttempts; attempt++)
            {
                try
                {
                    if (await action())
                    {
                        return true;
                    }
                }
                catch (Exception ex)
                {
                    Log.log("RetryPolicy", $"尝试 {attempt} 失败：{ex.Message}");
                }

                if (attempt < MaxRetryAttempts)
                {
                    await Task.Delay(RetryDelayMilliseconds);
                }
            }
            return false;
        }

        private void ReadFile()
        {
            try
            {
                var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lastFile.json");
                if (File.Exists(filePath))
                {
                    using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    using (var reader = new StreamReader(stream, Encoding.UTF8))
                    {
                        var json = reader.ReadToEnd();
                        LoginUser.lastFile = Newtonsoft.Json.JsonConvert.DeserializeObject<LastFile>(json);
                    }
                }
                else
                {
                    LoginUser.lastFile = new LastFile
                    {
                        LastPicTime = DateTime.MinValue,
                        LastRwjlTime = DateTime.MinValue,
                        LastVideoTime = DateTime.MinValue
                    };
                }
            }
            catch (Exception ex)
            {
                Log.log("ReadFile", $"读取lastFile异常：{ex.Message}");
                LoginUser.lastFile = new LastFile();
            }
        }
    }
}
